<html>
    <head>
        <title>实体类</title>
    </head>
    <body>
        <script>
             /*
                        一、实体类  Entity Class

                                    实体派生自Entity<TKey>类，如下所示：

                                            public class Book : Entity<Guid>
                                            {
                                                public string Name { get; set; }

                                                public float Price { get; set; }
                                            }

                                    如果不想从基Entity<TKey>类派生实体，可以直接实现IEntity<TKey>接口。

                                    Entity<TKey>类只是使用给定的主键类型定义了一个Id属性，即上面示例中的Guid。
                                        
                                    它可以是其他类型，如string、int、long，或者你需要的任何类型。
                                    
                                    
                                    1、带有 Guid 主键的实体

                                            如果你的实体的Id类型是Guid，则需要实施一些良好的实践：

                                                ①、创建一个构造函数，获取Id作为参数并传递给基类。

                                                    如果你不设置GUID ID，ABP会在保存时设置它，但最好在实体上有一个有效的ID，甚至在将其保存到数据库之前。

                                                ②、如果你使用接受参数的构造函数创建实体，请同时创建private或protected空构造函数。
                                                
                                                    这在你的数据库提供程序从数据库中读取你的实体时使用（在反序列化时）。
                                            
                                                ③、不要使用Guid.NewGuid()来设置Id！在从创建实体的代码传递Id时使用IGuidGenerator服务。

                                                        IGuidGenerator优化以生成顺序GUID，这对于关系数据库中的聚集索引至关重要。

                                            一个实体示例：

                                                    public class Book : Entity<Guid>
                                                    {
                                                        public string Name { get; set; }

                                                        public float Price { get; set; }

                                                        protected Book()
                                                        {

                                                        }

                                                        public Book(Guid id)
                                                        : base(id)
                                                        {

                                                        }
                                                    }

                                            应用程序服务中的用法示例：

                                                    public class BookAppService : ApplicationService, IBookAppService
                                                    {
                                                        private readonly IRepository<Book> _bookRepository;

                                                        public BookAppService(IRepository<Book> bookRepository)
                                                        {
                                                            _bookRepository = bookRepository;
                                                        }

                                                        public async Task CreateAsync(CreateBookDto input)
                                                        {
                                                            await _bookRepository.InsertAsync(
                                                                new Book(GuidGenerator.Create())
                                                                {
                                                                    Name = input.Name,
                                                                    Price = input.Price
                                                                }
                                                            );
                                                        }
                                                    }

                                                    BookAppService为图书实体注入默认的存储库，并使用其InsertAsync方法将Book插入数据库。

                                                    GuidGenerator是IGuidGenerator的类型，它是在ApplicationService基类中定义的属性。GuidGenerator是IGuidGenerator的类型，它是在ApplicationService基类中定义的属性。

                                                    如果你想遵循DDD最佳实践，请参阅下面的聚合示例部分。



                                    2、带有复合主键的实体

                                             某些实体可能需要具有复合键。在这种情况下，你可以从非泛型Entity类派生你的实体。
                                             
                                             例子：

                                                    public class UserRole : Entity // 复合主键提示集成非泛型Entity类
                                                    {
                                                        public Guid UserId { get; set; }

                                                        public Guid RoleId { get; set; }
                                                        
                                                        public DateTime CreationTime { get; set; }

                                                        public UserRole()
                                                        {
                                                                
                                                        }
                                                        
                                                        // 重写GetKeys()方法定义复合主键
                                                        public override object[] GetKeys()
                                                        {
                                                            return new object[] { UserId, RoleId }; // 复合键由UserId和RoleId组成
                                                        }
                                                    }
                                                
                                                对于上面的示例，复合键由UserId和RoleId组成。

                                                对于关系数据库，它是相关表的复合主键。具有复合键的实体应实现如上所示的GetKeys()方法。

                                            ★、请注意，你还需要在对象关系映射（ORM）配置中定义实体的键。例如，请参阅Entity Framework Core集成文档。

                                            ★、请注意，具有复合主键的实体不能使用IRepository<TEntity, TKey>接口，因为它需要单个Id属性。

                                                            但是，你始终可以使用IRepository<TEntity>。


                                    3、Entity.EntityEquals() 
                                                                
                                            Entity.EntityEquals(...)方法用于检查两个实体对象是否相等。

                                            eg:  

                                                Book book1 = ...
                                                Book book2 = ...

                                                if (book1.EntityEquals(book2)) //Check equality
                                                {
                                                    ...
                                                }
                    */
        </script>
    </body>
</html>